home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / ICMP.C < prev    next >
Text File  |  1993-08-09  |  6KB  |  258 lines

  1. /* Internet Control Message Protocol (ICMP)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "timer.h"
  8. #include "iface.h"
  9. #include "ip.h"
  10. #include "icmp.h"
  11. #include "netuser.h"
  12.  
  13. struct mib_entry Icmp_mib[] = {
  14.     "",                        0,
  15.     "InMsgs",            0,
  16.     "InErrors",            0,
  17.     "InDestUnreachs",    0,
  18.     "InTimeExcds",        0,
  19.     "InParmProbs",        0,
  20.     "InSrcQuenchs",        0,
  21.     "InRedirects",        0,
  22.     "InEchos",            0,
  23.     "InEchoReps",        0,
  24.     "InTimestamps",        0,
  25.     "InTimestampReps",    0,
  26.     "InAddrMasks",        0,
  27.     "InAddrMaskReps",    0,
  28.     "OutMsgs",            0,
  29.     "OutErrors",        0,
  30.     "OutDestUnreachs",    0,
  31.     "OutTimeExcds",        0,
  32.     "OutParmProbs",        0,
  33.     "OutSrcQuenchs",    0,
  34.     "OutRedirects",        0,
  35.     "OutEchos",            0,
  36.     "OutEchoReps",        0,
  37.     "OutTimestamps",    0,
  38.     "OutTimestampReps",    0,
  39.     "OutAddrMasks",        0,
  40.     "OutAddrMaskReps",    0,
  41. };
  42.  
  43. /* Process an incoming ICMP packet */
  44. void
  45. icmp_input(
  46. struct iface *iface,        /* Incoming interface (ignored) */
  47. struct ip *ip,                /* Pointer to decoded IP header structure */
  48. struct mbuf *bp,            /* Pointer to ICMP message */
  49. int rxbroadcast)
  50. {
  51.     struct icmplink *ipp;
  52.     struct mbuf *tbp;
  53.     struct icmp icmp;        /* ICMP header */
  54.     struct ip oip;            /* Offending datagram header */
  55.     unsigned char type;        /* Type of ICMP message */
  56.     int16 length;
  57.  
  58.     icmpInMsgs++;
  59.  
  60.     /* Broadcast ICMP packets are to be IGNORED !! */
  61.     if(rxbroadcast){
  62.         icmpInErrors++;
  63.         goto quit;
  64.     }
  65.     /* Bad ICMP checksum; discard */
  66.     if(cksum(NULLHEADER,bp,length = (ip->length - IPLEN - ip->optlen)) != 0) {
  67.         icmpInErrors++;
  68.         goto quit;
  69.     }
  70.     ntohicmp(&icmp,&bp);
  71.  
  72.     /* Process the message. Some messages are passed up to the protocol
  73.      * module for handling, others are handled here.
  74.      */
  75.     type = uchar(icmp.type);
  76.  
  77.     switch(type){
  78.     case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  79.     case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  80.     case ICMP_QUENCH:    /* Source Quench */
  81.         switch(type){
  82.         case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  83.             icmpInTimeExcds++;
  84.             break;
  85.         case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  86.             icmpInDestUnreachs++;
  87.             break;
  88.         case ICMP_QUENCH:    /* Source Quench */
  89.             icmpInSrcQuenchs++;
  90.             break;
  91.         }
  92.         ntohip(&oip,&bp);    /* Extract offending IP header */
  93.         if(Icmp_trace){
  94.             tprintf("ICMP from %s: ",inet_ntoa(ip->source));
  95.             tprintf("dest %s %s ",
  96.                 inet_ntoa(oip.dest),Icmptypes[type]);
  97.             switch(type) {
  98.             case ICMP_TIME_EXCEED:
  99.                 tprintf("%s\n",Exceed[uchar(icmp.code)]);
  100.                 break;
  101.             case ICMP_DEST_UNREACH:
  102.                 tprintf("%s\n",Unreach[uchar(icmp.code)]);
  103.                 break;
  104.             default:
  105.                 tprintf("%u\n",uchar(icmp.code));
  106.                 break;
  107.             }
  108.         }
  109.         for(ipp = Icmplink; ipp->funct != NULL; ipp++)
  110.             if(ipp->proto == oip.protocol)
  111.                 break;
  112.         if(ipp->funct != NULL){
  113.             (*ipp->funct)(ip->source,oip.source,oip.dest,icmp.type,icmp.code,&bp);
  114.         }
  115.         break;
  116.     case ICMP_ECHO:        /* Echo Request */
  117.         /* Change type to ECHO_REPLY, recompute checksum,
  118.          * and return datagram.
  119.          */
  120.         icmpInEchos++;
  121.         icmpOutEchoReps++;
  122.         icmp.type = ICMP_ECHO_REPLY;
  123.         tbp = htonicmp(&icmp,bp);
  124.         ip_send(ip->dest,ip->source,ICMP_PTCL,ip->tos,0,tbp,length,0,0);
  125.         return;
  126.     case ICMP_REDIRECT:    /* Redirect */
  127.         icmpInRedirects++;
  128.         break;
  129.     case ICMP_PARAM_PROB:    /* Parameter Problem */
  130.         icmpInParmProbs++;
  131.         break;
  132.     case ICMP_ECHO_REPLY:    /* Echo Reply */
  133.         icmpInEchoReps++;
  134.         echo_proc(ip->source,ip->dest,&icmp,bp);
  135.         bp = NULLBUF;    /* so it won't get freed */
  136.         break;
  137.     case ICMP_TIMESTAMP:    /* Timestamp */
  138.         icmpInTimestamps++;
  139.         break;
  140.     case ICMP_TIME_REPLY:    /* Timestamp Reply */
  141.         icmpInTimestampReps++;
  142.         break;
  143.     case ICMP_INFO_RQST:    /* Information Request */
  144.     case ICMP_INFO_REPLY:    /* Information Reply */
  145.         break;
  146.     }
  147. quit:
  148.     free_p(bp);
  149.     return;
  150. }
  151.  
  152. /* Return an ICMP response to the sender of a datagram.
  153.  * Unlike most routines, the callER frees the mbuf.
  154.  */
  155. int
  156. icmp_output(
  157. struct ip *ip,                /* Header of offending datagram */
  158. struct mbuf *data,            /* Data portion of datagram */
  159. char type,char code,        /* Codes to send */
  160. union icmp_args *args)
  161. {
  162.     struct mbuf *bp = NULLBUF;
  163.     struct icmp icmp;        /* ICMP protocol header */
  164.     int16 dlen;                /* Length of data portion of offending pkt */
  165.     int16 length;            /* Total length of reply */
  166.  
  167.     if(ip == NULLIP)
  168.         return -1;
  169.  
  170.     if(uchar(ip->protocol) == ICMP_PTCL) {
  171.         /* Peek at type field of ICMP header to see if it's safe to
  172.          * return an ICMP message
  173.          */
  174.         switch(uchar(data->data[0])){
  175.         case ICMP_ECHO_REPLY:
  176.         case ICMP_ECHO:
  177.         case ICMP_TIMESTAMP:
  178.         case ICMP_TIME_REPLY:
  179.         case ICMP_INFO_RQST:
  180.         case ICMP_INFO_REPLY:
  181.             break;    /* These are all safe */
  182.         default:
  183.             /* Never send an ICMP error message about another
  184.              * ICMP error message!
  185.              */
  186.             return -1;
  187.         }
  188.     }
  189.     /* Compute amount of original datagram to return.
  190.      * We return the original IP header, and up to 8 bytes past that.
  191.      */
  192.     if((dlen = len_p(data)) > 8)
  193.         dlen = 8;
  194.  
  195.     length = dlen + ICMPLEN + IPLEN + ip->optlen;
  196.  
  197.     /* Take excerpt from data portion */
  198.     if(dup_p(&bp,data,0,dlen) == 0)
  199.         return -1;    /* The caller will free data */
  200.  
  201.     /* Recreate and tack on offending IP header */
  202.     data = htonip(ip,bp,0);
  203.  
  204.     icmp.type = type;
  205.     icmp.code = code;
  206.     icmp.args.unused = 0;
  207.  
  208.     switch(uchar(icmp.type)){
  209.     case ICMP_PARAM_PROB:
  210.         icmpOutParmProbs++;
  211.         icmp.args.pointer = args->pointer;
  212.         break;
  213.     case ICMP_REDIRECT:
  214.         icmpOutRedirects++;
  215.         icmp.args.address = args->address;
  216.         break;
  217.     case ICMP_ECHO:
  218.         icmpOutEchos++;
  219.         break;
  220.     case ICMP_ECHO_REPLY:
  221.         icmpOutEchoReps++;
  222.         break;
  223.     case ICMP_INFO_RQST:
  224.     case ICMP_INFO_REPLY:
  225.         break;
  226.     case ICMP_TIMESTAMP:
  227.         icmpOutTimestamps++;
  228.         break;
  229.     case ICMP_TIME_REPLY:
  230.         icmpOutTimestampReps++;
  231.         icmp.args.echo.id = args->echo.id;
  232.         icmp.args.echo.seq = args->echo.seq;
  233.         break;
  234.     case ICMP_ADDR_MASK:
  235.         icmpOutAddrMasks++;
  236.         break;
  237.     case ICMP_ADDR_MASK_REPLY:
  238.         icmpOutAddrMaskReps++;
  239.         break;
  240.     case ICMP_DEST_UNREACH:
  241.         if(icmp.code == ICMP_FRAG_NEEDED)
  242.             icmp.args.mtu = args->mtu;
  243.         icmpOutDestUnreachs++;
  244.         break;
  245.     case ICMP_TIME_EXCEED:
  246.         icmpOutTimeExcds++;
  247.         break;
  248.     case ICMP_QUENCH:
  249.         icmpOutSrcQuenchs++;
  250.         break;
  251.     }
  252.     icmpOutMsgs++;
  253.  
  254.     /* Now stick on the ICMP header */
  255.     bp = htonicmp(&icmp,data);
  256.     return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  257. }
  258.